package com.sourceQ.system.service.message.mail.impl;

import cn.hutool.Hutool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import com.google.common.annotations.VisibleForTesting;
import com.sourceQ.common.core.constant.dict.BmMessageStatus;
import com.sourceQ.system.domain.message.mail.SysMailAccount;
import com.sourceQ.system.domain.message.mail.SysMailTemplate;
import com.sourceQ.system.mq.mail.producer.MailProducer;
import com.sourceQ.system.mq.mail.vo.MailSendMessage;
import com.sourceQ.system.service.message.mail.SysMailAccountService;
import com.sourceQ.system.service.message.mail.SysMailLogService;
import com.sourceQ.system.service.message.mail.SysMailSendService;
import com.sourceQ.system.service.message.mail.SysMailTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Map;

import static com.sourceQ.common.core.constant.ErrorCodeConstants.*;
import static com.sourceQ.common.core.utils.ExceptionUtil.exception;

/**
 * @author: SourceQ
 * @create: 2024-04-18 20:17
 * @Description:
 */
@Service
public class SysMailSendServiceImpl implements SysMailSendService {
    @Autowired
    private SysMailTemplateService mailTemplateService;
    @Autowired
    private SysMailLogService mailLogService;
    @Autowired
    private SysMailAccountService mailAccountService;
    @Autowired
    private MailProducer mailProducer;

    @Override
    public Long sendSingleMailToAdmin(String mail, Long userId, String templateCode, Map<String, Object> templateParams) {
        return null;
    }

    @Override
    public Long sendSingleMailToMember(String mail, Long userId, String templateCode, Map<String, Object> templateParams) {
        return null;
    }

    @Override
    public Long sendSingleMail(String mail, Long userId, Integer userType, String templateCode, Map<String, Object> templateParams) {
        // 校验邮箱模版是否合法
        SysMailTemplate template = validateMailTemplate(templateCode);
        // 校验邮箱账号是否合法
        SysMailAccount account = validateMailAccount(template.getAccountId());
        // 校验邮箱是否存在
        mail = validateMail(mail);
        validateTemplateParams(template, templateParams);

        // 创建发送日志。如果模板被禁用，则不发送短信，只记录日志
        Boolean isSend = BmMessageStatus.ENABLE.equals(template.getStatus());
        String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams);
        String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
        Long sendLogId = mailLogService.createMailLog(userId, userType, mail,
                account, template, content, templateParams, isSend);
        // 发送 MQ 消息，异步执行发送短信
        if (isSend) {
            mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
                    template.getNickname(), title, content);
        }
        return sendLogId;
    }

    @Override
    public void doSendMail(MailSendMessage message) {
        // 1. 创建发送账号
        SysMailAccount account = validateMailAccount(message.getAccountId());
        MailAccount mailAccount = convert(account,message.getNickname());
        // 2. 发送邮件
        try {
            String messageId = MailUtil.send(mailAccount, message.getMail(),
                    message.getTitle(), message.getContent(), true);
            // 3. 更新结果（成功）
            mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
        } catch (Exception e) {
            // 3. 更新结果（异常）
            mailLogService.updateMailSendResult(message.getLogId(), null, e);
        }
    }

    /**
     * 校验账号是否存在
     *
     * @param accountId
     * @return
     */
    @VisibleForTesting
    //为了方便测试而暴露出来的，在正常生产环境中使用,需考虑周全后方可使用
    SysMailAccount validateMailAccount(Long accountId) {
        // 获得邮箱账号。考虑到效率，从缓存中获取
        SysMailAccount account = mailAccountService.getMailAccountFromCache(accountId);
        // 邮箱账号不存在
        if (account == null) {
            throw exception(MAIL_ACCOUNT_NOT_EXISTS);
        }
        return account;
    }

    /**
     * 校验邮箱是否存在
     *
     * @param mail
     * @return
     */
    String validateMail(String mail) {
        if (StrUtil.isEmpty(mail)) {
            throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
        }
        return mail;
    }

    /**
     * 模板是否存在
     *
     * @param templateCode
     * @return
     */
    SysMailTemplate validateMailTemplate(String templateCode) {
        // 获得邮件模板。考虑到效率，从缓存中获取
        SysMailTemplate template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode);
        // 邮件模板不存在
        if (template == null) {
            throw exception(MAIL_TEMPLATE_NOT_EXISTS);
        }
        return template;
    }

    /**
     * 校验邮件参数是否确实
     *
     * @param template       邮箱模板
     * @param templateParams 参数列表
     */
    void validateTemplateParams(SysMailTemplate template, Map<String, Object> templateParams) {
        if (!CollectionUtils.isEmpty(template.getParams())) {
            template.getParams().forEach(key -> {
                Object value = templateParams.get(key);
                if (value == null) {
                    throw exception(MAIL_SEND_TEMPLATE_PARAM_MISS, key);
                }
            });
        }
    }

    /**
     * 数据裁剪
     * @param account
     * @param nickname
     * @return
     */
    private MailAccount convert(SysMailAccount account, String nickname){
        String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
        return new MailAccount().setFrom(from).setAuth(true)
                .setUser(account.getUsername()).setPass(account.getPassword())
                .setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable());
    }
}
